package edu.ubc.javascript;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.google.javascript.jscomp.mozilla.rhino.ast.FunctionNode;

public class FunctionNodeScopeInfo {
	private FunctionNode fn;
	public String getName() { return fn.getName(); } 
	private Set<String> closureVariables = new HashSet<String>();
	private Set<FunctionNodeScopeInfo> parents = new HashSet<FunctionNodeScopeInfo>();
	private Set<FunctionNodeScopeInfo> children = new HashSet<FunctionNodeScopeInfo>();
	private Map<String, Integer> closedVars = new HashMap<String, Integer>();
	private Set<String> prohibited = new HashSet<String>();
	private boolean hasChildren = false;
	
	public boolean hasChildren() {
		return hasChildren;
	}
	
	public void setHasChildren() {
		hasChildren = true;
	}
	
	public Set<String> getClosureVariables() {
		return closureVariables;
	}
	
	public void addClosureVariable(String name) {
		closureVariables.add(name);
	}
	
	public Map<String, Integer> getClosedVars() {
		return closedVars;
	}
	
	public boolean isProhibited(String name) {
		return prohibited.contains(name);
	}
	
	public void prohibitClosureVar(String name) {
		closedVars.remove(name);
		prohibited.add(name);
	}
	
	public void addClosedVar(String name, Integer up) {
		if(!prohibited.contains(name)) {
			closedVars.put(name, up);
		}
	}
	
	private boolean onClosurePath = false;
	public boolean isOnClosurePath() { return onClosurePath; } 
	
	public String toString(int indent) {
		String retVal = "";
		for(int i=0; i < indent; i++) {
			retVal += '\t';
		}
		retVal += fn.getName() + "\n";
		for(FunctionNodeScopeInfo fnci : children) {
			retVal += fnci.toString(indent + 1);
		}
		return retVal;
	}
	
	public FunctionNodeScopeInfo(FunctionNode fn) {
		this.fn = fn;
	}
	
	public void setOnClosurePath() {
		onClosurePath = true;
	}
	
	public void addParent(FunctionNodeScopeInfo parent) {
		onClosurePath = true;
		parents.add(parent);
	}
	
	public void addChild(FunctionNodeScopeInfo child) {
		onClosurePath = true;
		children.add(child);
	}
	
	public Set<FunctionNodeScopeInfo> getParent() {
		return parents;
	}
	
	public Set<FunctionNodeScopeInfo> getChildren() {
		return children;
	}

	public int maxHeight() {
		int maxHeight = 0;
		for(Integer val : closedVars.values()) {
			if(val > maxHeight) {
				maxHeight = val;
			}
		}
		return maxHeight;
	}
}
